1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.collect.Maps.immutableEntry;
20  
21  import com.google.common.collect.testing.NavigableMapTestSuiteBuilder;
22  import com.google.common.collect.testing.SafeTreeMap;
23  import com.google.common.collect.testing.TestStringSortedMapGenerator;
24  import com.google.common.collect.testing.features.CollectionFeature;
25  import com.google.common.collect.testing.features.CollectionSize;
26  import com.google.common.collect.testing.features.MapFeature;
27  
28  import junit.framework.Test;
29  import junit.framework.TestSuite;
30  
31  import java.util.Collection;
32  import java.util.Iterator;
33  import java.util.Map;
34  import java.util.Map.Entry;
35  import java.util.NavigableMap;
36  import java.util.NavigableSet;
37  import java.util.Set;
38  import java.util.SortedMap;
39  
40  /**
41   * Tests for {@code ForwardingNavigableMap}.
42   *
43   * @author Robert Konigsberg
44   * @author Louis Wasserman
45   */
46  public class ForwardingNavigableMapTest extends ForwardingSortedMapTest {
47    static class StandardImplForwardingNavigableMap<K, V>
48        extends ForwardingNavigableMap<K, V> {
49      private final NavigableMap<K, V> backingMap;
50  
51      StandardImplForwardingNavigableMap(NavigableMap<K, V> backingMap) {
52        this.backingMap = backingMap;
53      }
54  
55      @Override protected NavigableMap<K, V> delegate() {
56        return backingMap;
57      }
58  
59      @Override public boolean containsKey(Object key) {
60        return standardContainsKey(key);
61      }
62  
63      @Override public boolean containsValue(Object value) {
64        return standardContainsValue(value);
65      }
66  
67      @Override public void putAll(Map<? extends K, ? extends V> map) {
68        standardPutAll(map);
69      }
70  
71      @Override public V remove(Object object) {
72        return standardRemove(object);
73      }
74  
75      @Override public boolean equals(Object object) {
76        return standardEquals(object);
77      }
78  
79      @Override public int hashCode() {
80        return standardHashCode();
81      }
82  
83      @Override public Set<K> keySet() {
84        /*
85         * We can't use StandardKeySet, as NavigableMapTestSuiteBuilder assumes that our keySet is a
86         * NavigableSet. We test StandardKeySet in the superclass, so it's still covered.
87         */
88        return navigableKeySet();
89      }
90  
91      @Override public Collection<V> values() {
92        return new StandardValues();
93      }
94  
95      @Override public String toString() {
96        return standardToString();
97      }
98  
99      @Override public Set<Entry<K, V>> entrySet() {
100       return new StandardEntrySet() {
101         @Override
102         public Iterator<Entry<K, V>> iterator() {
103           return backingMap.entrySet().iterator();
104         }
105       };
106     }
107 
108     @Override public void clear() {
109       standardClear();
110     }
111 
112     @Override public boolean isEmpty() {
113       return standardIsEmpty();
114     }
115 
116     @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
117       return standardSubMap(fromKey, toKey);
118     }
119 
120     @Override
121     public Entry<K, V> lowerEntry(K key) {
122       return standardLowerEntry(key);
123     }
124 
125     @Override
126     public K lowerKey(K key) {
127       return standardLowerKey(key);
128     }
129 
130     @Override
131     public Entry<K, V> floorEntry(K key) {
132       return standardFloorEntry(key);
133     }
134 
135     @Override
136     public K floorKey(K key) {
137       return standardFloorKey(key);
138     }
139 
140     @Override
141     public Entry<K, V> ceilingEntry(K key) {
142       return standardCeilingEntry(key);
143     }
144 
145     @Override
146     public K ceilingKey(K key) {
147       return standardCeilingKey(key);
148     }
149 
150     @Override
151     public Entry<K, V> higherEntry(K key) {
152       return standardHigherEntry(key);
153     }
154 
155     @Override
156     public K higherKey(K key) {
157       return standardHigherKey(key);
158     }
159 
160     @Override
161     public Entry<K, V> firstEntry() {
162       return standardFirstEntry();
163     }
164 
165     /*
166      * We can't override lastEntry to delegate to standardLastEntry, as it would create an infinite
167      * loop. Instead, we test standardLastEntry manually below.
168      */
169 
170     @Override
171     public Entry<K, V> pollFirstEntry() {
172       return standardPollFirstEntry();
173     }
174 
175     @Override
176     public Entry<K, V> pollLastEntry() {
177       return standardPollLastEntry();
178     }
179 
180     @Override
181     public NavigableMap<K, V> descendingMap() {
182       return new StandardDescendingMap();
183     }
184 
185     @Override
186     public NavigableSet<K> navigableKeySet() {
187       return new StandardNavigableKeySet();
188     }
189 
190     @Override
191     public NavigableSet<K> descendingKeySet() {
192       return standardDescendingKeySet();
193     }
194 
195     @Override
196     public K firstKey() {
197       return standardFirstKey();
198     }
199 
200     @Override
201     public SortedMap<K, V> headMap(K toKey) {
202       return standardHeadMap(toKey);
203     }
204 
205     @Override
206     public K lastKey() {
207       return standardLastKey();
208     }
209 
210     @Override
211     public SortedMap<K, V> tailMap(K fromKey) {
212       return standardTailMap(fromKey);
213     }
214   }
215 
216   static class StandardLastEntryForwardingNavigableMap<K, V>
217       extends ForwardingNavigableMap<K, V> {
218     private final NavigableMap<K, V> backingMap;
219 
220     StandardLastEntryForwardingNavigableMap(NavigableMap<K, V> backingMap) {
221       this.backingMap = backingMap;
222     }
223 
224     @Override protected NavigableMap<K, V> delegate() {
225       return backingMap;
226     }
227 
228     @Override
229     public Entry<K, V> lastEntry() {
230       return standardLastEntry();
231     }
232   }
233 
234   public static Test suite() {
235     TestSuite suite = new TestSuite();
236 
237     suite.addTestSuite(ForwardingNavigableMapTest.class);
238     suite.addTest(NavigableMapTestSuiteBuilder.using(new TestStringSortedMapGenerator() {
239       @Override protected SortedMap<String, String> create(
240           Entry<String, String>[] entries) {
241         NavigableMap<String, String> map = new SafeTreeMap<String, String>();
242         for (Entry<String, String> entry : entries) {
243           map.put(entry.getKey(), entry.getValue());
244         }
245         return new StandardImplForwardingNavigableMap<String, String>(map);
246       }
247     }).named("ForwardingNavigableMap[SafeTreeMap] with no comparator and standard "
248         + "implementations").withFeatures(CollectionSize.ANY,
249         CollectionFeature.KNOWN_ORDER, MapFeature.ALLOWS_NULL_VALUES,
250         CollectionFeature.SUPPORTS_ITERATOR_REMOVE, MapFeature.GENERAL_PURPOSE)
251         .createTestSuite());
252     // TODO(user): add forwarding-to-ImmutableSortedMap test
253     return suite;
254   }
255 
256   @Override public void setUp() throws Exception {
257     super.setUp();
258     /*
259      * Class parameters must be raw, so we can't create a proxy with generic
260      * type arguments. The created proxy only records calls and returns null, so
261      * the type is irrelevant at runtime.
262      */
263     @SuppressWarnings("unchecked")
264     final NavigableMap<String, Boolean> sortedMap =
265         createProxyInstance(NavigableMap.class);
266     forward = new ForwardingNavigableMap<String, Boolean>() {
267       @Override protected NavigableMap<String, Boolean> delegate() {
268         return sortedMap;
269       }
270     };
271   }
272 
273   public void testStandardLastEntry() {
274     NavigableMap<String, Integer> forwarding =
275         new StandardLastEntryForwardingNavigableMap<String, Integer>(
276             new SafeTreeMap<String, Integer>());
277     assertNull(forwarding.lastEntry());
278     forwarding.put("b", 2);
279     assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
280     forwarding.put("c", 3);
281     assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
282     forwarding.put("a", 1);
283     assertEquals(immutableEntry("c", 3), forwarding.lastEntry());
284     forwarding.remove("c");
285     assertEquals(immutableEntry("b", 2), forwarding.lastEntry());
286   }
287 
288   public void testLowerEntry() {
289     forward().lowerEntry("key");
290     assertEquals("[lowerEntry(Object)]", getCalls());
291   }
292 
293   public void testLowerKey() {
294     forward().lowerKey("key");
295     assertEquals("[lowerKey(Object)]", getCalls());
296   }
297 
298   public void testFloorEntry() {
299     forward().floorEntry("key");
300     assertEquals("[floorEntry(Object)]", getCalls());
301   }
302 
303   public void testFloorKey() {
304     forward().floorKey("key");
305     assertEquals("[floorKey(Object)]", getCalls());
306   }
307 
308   public void testCeilingEntry() {
309     forward().ceilingEntry("key");
310     assertEquals("[ceilingEntry(Object)]", getCalls());
311   }
312 
313   public void testCeilingKey() {
314     forward().ceilingKey("key");
315     assertEquals("[ceilingKey(Object)]", getCalls());
316   }
317 
318   public void testHigherEntry() {
319     forward().higherEntry("key");
320     assertEquals("[higherEntry(Object)]", getCalls());
321   }
322 
323   public void testHigherKey() {
324     forward().higherKey("key");
325     assertEquals("[higherKey(Object)]", getCalls());
326   }
327 
328   public void testPollFirstEntry() {
329     forward().pollFirstEntry();
330     assertEquals("[pollFirstEntry]", getCalls());
331   }
332 
333   public void testPollLastEntry() {
334     forward().pollLastEntry();
335     assertEquals("[pollLastEntry]", getCalls());
336   }
337 
338   public void testFirstEntry() {
339     forward().firstEntry();
340     assertEquals("[firstEntry]", getCalls());
341   }
342 
343   public void testLastEntry() {
344     forward().lastEntry();
345     assertEquals("[lastEntry]", getCalls());
346   }
347 
348   public void testDescendingMap() {
349     forward().descendingMap();
350     assertEquals("[descendingMap]", getCalls());
351   }
352 
353   public void testNavigableKeySet() {
354     forward().navigableKeySet();
355     assertEquals("[navigableKeySet]", getCalls());
356   }
357 
358   public void testDescendingKeySet() {
359     forward().descendingKeySet();
360     assertEquals("[descendingKeySet]", getCalls());
361   }
362 
363   public void testSubMap_K_Bool_K_Bool() {
364     forward().subMap("a", false, "b", true);
365     assertEquals("[subMap(Object,boolean,Object,boolean)]", getCalls());
366   }
367 
368   public void testHeadMap_K_Bool() {
369     forward().headMap("a", false);
370     assertEquals("[headMap(Object,boolean)]", getCalls());
371   }
372 
373   public void testTailMap_K_Bool() {
374     forward().tailMap("a", false);
375     assertEquals("[tailMap(Object,boolean)]", getCalls());
376   }
377 
378   @Override NavigableMap<String, Boolean> forward() {
379     return (NavigableMap<String, Boolean>) super.forward();
380   }
381 }